home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / emacs_src_18_58.lha / emacs-18.58 / lisp / gdb.el < prev    next >
Lisp/Scheme  |  1992-02-21  |  14KB  |  398 lines

  1. ;; Run gdb under Emacs
  2. ;; Copyright (C) 1988 Free Software Foundation, Inc.
  3.  
  4. ;; This file is part of GNU Emacs.
  5.  
  6. ;; GNU Emacs is free software; you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation; either version 1, or (at your option)
  9. ;; any later version.
  10.  
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ;; GNU General Public License for more details.
  15.  
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs; see the file COPYING.  If not, write to
  18. ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20. ;; Author: W. Schelter, University of Texas
  21. ;;     wfs@rascal.ics.utexas.edu
  22. ;; Rewritten by rms.
  23.  
  24. ;; Some ideas are due to  Masanobu. 
  25.  
  26. ;; Description of GDB interface:
  27.  
  28. ;; A facility is provided for the simultaneous display of the source code
  29. ;; in one window, while using gdb to step through a function in the
  30. ;; other.  A small arrow in the source window, indicates the current
  31. ;; line.
  32.  
  33. ;; Starting up:
  34.  
  35. ;; In order to use this facility, invoke the command GDB to obtain a
  36. ;; shell window with the appropriate command bindings.  You will be asked
  37. ;; for the name of a file to run.  Gdb will be invoked on this file, in a
  38. ;; window named *gdb-foo* if the file is foo.
  39.  
  40. ;; M-s steps by one line, and redisplays the source file and line.
  41.  
  42. ;; You may easily create additional commands and bindings to interact
  43. ;; with the display.  For example to put the gdb command next on \M-n
  44. ;; (def-gdb next "\M-n")
  45.  
  46. ;; This causes the emacs command gdb-next to be defined, and runs
  47. ;; gdb-display-frame after the command.
  48.  
  49. ;; gdb-display-frame is the basic display function.  It tries to display
  50. ;; in the other window, the file and line corresponding to the current
  51. ;; position in the gdb window.  For example after a gdb-step, it would
  52. ;; display the line corresponding to the position for the last step.  Or
  53. ;; if you have done a backtrace in the gdb buffer, and move the cursor
  54. ;; into one of the frames, it would display the position corresponding to
  55. ;; that frame.
  56.  
  57. ;; gdb-display-frame is invoked automatically when a filename-and-line-number
  58. ;; appears in the output.
  59.  
  60.  
  61. (require 'shell)
  62.  
  63. (defvar gdb-prompt-pattern "^(.*gdb[+]?) *"
  64.   "A regexp to recognize the prompt for gdb or gdb+.") 
  65.  
  66. (defvar gdb-mode-map nil
  67.   "Keymap for gdb-mode.")
  68.  
  69. (if gdb-mode-map
  70.    nil
  71.   (setq gdb-mode-map (copy-keymap shell-mode-map))
  72.   (define-key gdb-mode-map "\C-l" 'gdb-refresh))
  73.  
  74. (define-key ctl-x-map " " 'gdb-break)
  75. (define-key ctl-x-map "&" 'send-gdb-command)
  76.  
  77. ;;Of course you may use `def-gdb' with any other gdb command, including
  78. ;;user defined ones.   
  79.  
  80. (defmacro def-gdb (name key &optional doc)
  81.   (let* ((fun (intern (format "gdb-%s" name)))
  82.      (cstr (list 'if '(not (= 1 arg))
  83.              (list 'format "%s %s" name 'arg)
  84.              name)))
  85.     (list 'progn
  86.        (list 'defun fun '(arg)
  87.         (or doc "")
  88.         '(interactive "p")
  89.         (list 'gdb-call cstr))
  90.       (list 'define-key 'gdb-mode-map key  (list 'quote fun)))))
  91.  
  92. (def-gdb "step"   "\M-s" "Step one source line with display")
  93. (def-gdb "stepi"  "\M-i" "Step one instruction with display")
  94. (def-gdb "next"   "\M-n" "Step one source line (skip functions)")
  95. (def-gdb "cont"   "\M-c" "Continue with display")
  96.  
  97. (def-gdb "finish" "\C-c\C-f" "Finish executing current function")
  98. (def-gdb "up"     "\M-u"   "Go up N stack frames (numeric arg) with display")
  99. (def-gdb "down"   "\M-d"   "Go down N stack frames (numeric arg) with display")
  100.  
  101. (defun gdb-mode ()
  102.   "Major mode for interacting with an inferior Gdb process.
  103. The following commands are available:
  104.  
  105. \\{gdb-mode-map}
  106.  
  107. \\[gdb-display-frame] displays in the other window
  108. the last line referred to in the gdb buffer.
  109.  
  110. \\[gdb-step],\\[gdb-next], and \\[gdb-nexti] in the gdb window,
  111. call gdb to step,next or nexti and then update the other window
  112. with the current file and position.
  113.  
  114. If you are in a source file, you may select a point to break
  115. at, by doing \\[gdb-break].
  116.  
  117. Commands:
  118. Many commands are inherited from shell mode. 
  119. Additionally we have:
  120.  
  121. \\[gdb-display-frame] display frames file in other window
  122. \\[gdb-step] advance one line in program
  123. \\[gdb-next] advance one line in program (skip over calls).
  124. \\[send-gdb-command] used for special printing of an arg at the current point.
  125. C-x SPACE sets break point at current line."
  126.   (interactive)
  127.   (kill-all-local-variables)
  128.   (setq major-mode 'gdb-mode)
  129.   (setq mode-name "Inferior Gdb")
  130.   (setq mode-line-process '(": %s"))
  131.   (use-local-map gdb-mode-map)
  132.   (make-local-variable 'last-input-start)
  133.   (setq last-input-start (make-marker))
  134.   (make-local-variable 'last-input-end)
  135.   (setq last-input-end (make-marker))
  136.   (make-local-variable 'gdb-last-frame)
  137.   (setq gdb-last-frame nil)
  138.   (make-local-variable 'gdb-last-frame-displayed-p)
  139.   (setq gdb-last-frame-displayed-p t)
  140.   (make-local-variable 'gdb-delete-prompt-marker)
  141.   (setq gdb-delete-prompt-marker nil)
  142.   (make-local-variable 'gdb-filter-accumulator)
  143.   (setq gdb-filter-accumulator nil)
  144.   (make-local-variable 'shell-prompt-pattern)
  145.   (setq shell-prompt-pattern gdb-prompt-pattern)
  146.   (run-hooks 'shell-mode-hook 'gdb-mode-hook))
  147.  
  148. (defvar current-gdb-buffer nil)
  149.  
  150. (defvar gdb-command-name "gdb"
  151.   "Pathname for executing gdb.")
  152.  
  153. (defun gdb (path)
  154.   "Run gdb on program FILE in buffer *gdb-FILE*.
  155. The directory containing FILE becomes the initial working directory
  156. and source-file directory for GDB.  If you wish to change this, use
  157. the GDB commands `cd DIR' and `directory'."
  158.   (interactive "FRun gdb on file: ")
  159.   (setq path (expand-file-name path))
  160.   (let ((file (file-name-nondirectory path)))
  161.     (switch-to-buffer (concat "*gdb-" file "*"))
  162.     (setq default-directory (file-name-directory path))
  163.     (or (bolp) (newline))
  164.     (insert "Current directory is " default-directory "\n")
  165.     (make-shell (concat "gdb-" file) gdb-command-name nil "-fullname"
  166.         "-cd" default-directory file)
  167.     (gdb-mode)
  168.     (set-process-filter (get-buffer-process (current-buffer)) 'gdb-filter)
  169.     (set-process-sentinel (get-buffer-process (current-buffer)) 'gdb-sentinel)
  170.     (gdb-set-buffer)))
  171.  
  172. (defun gdb-set-buffer ()
  173.   (cond ((eq major-mode 'gdb-mode)
  174.     (setq current-gdb-buffer (current-buffer)))))
  175.  
  176. ;; This function is responsible for inserting output from GDB
  177. ;; into the buffer.
  178. ;; Aside from inserting the text, it notices and deletes
  179. ;; each filename-and-line-number;
  180. ;; that GDB prints to identify the selected frame.
  181. ;; It records the filename and line number, and maybe displays that file.
  182. (defun gdb-filter (proc string)
  183.   (let ((inhibit-quit t))
  184.     (if gdb-filter-accumulator
  185.     (gdb-filter-accumulate-marker proc
  186.                       (concat gdb-filter-accumulator string))
  187.     (gdb-filter-scan-input proc string))))
  188.  
  189. (defun gdb-filter-accumulate-marker (proc string)
  190.   (setq gdb-filter-accumulator nil)
  191.   (if (> (length string) 1)
  192.       (if (= (aref string 1) ?\032)
  193.       (let ((end (string-match "\n" string)))
  194.         (if end
  195.         (progn
  196.           (let* ((first-colon (string-match ":" string 2))
  197.              (second-colon
  198.               (string-match ":" string (1+ first-colon))))
  199.             (setq gdb-last-frame
  200.               (cons (substring string 2 first-colon)
  201.                 (string-to-int
  202.                  (substring string (1+ first-colon)
  203.                         second-colon)))))
  204.           (setq gdb-last-frame-displayed-p nil)
  205.           (gdb-filter-scan-input proc
  206.                      (substring string (1+ end))))
  207.           (setq gdb-filter-accumulator string)))
  208.     (gdb-filter-insert proc "\032")
  209.     (gdb-filter-scan-input proc (substring string 1)))
  210.     (setq gdb-filter-accumulator string)))
  211.  
  212. (defun gdb-filter-scan-input (proc string)
  213.   (if (equal string "")
  214.       (setq gdb-filter-accumulator nil)
  215.       (let ((start (string-match "\032" string)))
  216.     (if start
  217.         (progn (gdb-filter-insert proc (substring string 0 start))
  218.            (gdb-filter-accumulate-marker proc
  219.                          (substring string start)))
  220.         (gdb-filter-insert proc string)))))
  221.  
  222. (defun gdb-filter-insert (proc string)
  223.   (let ((moving (= (point) (process-mark proc)))
  224.     (output-after-point (< (point) (process-mark proc)))
  225.     (old-buffer (current-buffer))
  226.     start)
  227.     (set-buffer (process-buffer proc))
  228.     (unwind-protect
  229.     (save-excursion
  230.       ;; Insert the text, moving the process-marker.
  231.       (goto-char (process-mark proc))
  232.       (setq start (point))
  233.       (insert string)
  234.       (set-marker (process-mark proc) (point))
  235.       (gdb-maybe-delete-prompt)
  236.       ;; Check for a filename-and-line number.
  237.       (gdb-display-frame
  238.        ;; Don't display the specified file
  239.        ;; unless (1) point is at or after the position where output appears
  240.        ;; and (2) this buffer is on the screen.
  241.        (or output-after-point
  242.            (not (get-buffer-window (current-buffer))))
  243.        ;; Display a file only when a new filename-and-line-number appears.
  244.        t))
  245.       (set-buffer old-buffer))
  246.     (if moving (goto-char (process-mark proc)))))
  247.  
  248. (defun gdb-sentinel (proc msg)
  249.   (cond ((null (buffer-name (process-buffer proc)))
  250.      ;; buffer killed
  251.      ;; Stop displaying an arrow in a source file.
  252.      (setq overlay-arrow-position nil)
  253.      (set-process-buffer proc nil))
  254.     ((memq (process-status proc) '(signal exit))
  255.      ;; Stop displaying an arrow in a source file.
  256.      (setq overlay-arrow-position nil)
  257.      ;; Fix the mode line.
  258.      (setq mode-line-process
  259.            (concat ": "
  260.                (symbol-name (process-status proc))))
  261.      (let* ((obuf (current-buffer)))
  262.        ;; save-excursion isn't the right thing if
  263.        ;;  process-buffer is current-buffer
  264.        (unwind-protect
  265.            (progn
  266.          ;; Write something in *compilation* and hack its mode line,
  267.          (set-buffer (process-buffer proc))
  268.          ;; Force mode line redisplay soon
  269.          (set-buffer-modified-p (buffer-modified-p))
  270.          (if (eobp)
  271.              (insert ?\n mode-name " " msg)
  272.            (save-excursion
  273.              (goto-char (point-max))
  274.              (insert ?\n mode-name " " msg)))
  275.          ;; If buffer and mode line will show that the process
  276.          ;; is dead, we can delete it now.  Otherwise it
  277.          ;; will stay around until M-x list-processes.
  278.          (delete-process proc))
  279.          ;; Restore old buffer, but don't restore old point
  280.          ;; if obuf is the gdb buffer.
  281.          (set-buffer obuf))))))
  282.  
  283.  
  284. (defun gdb-refresh ()
  285.   "Fix up a possibly garbled display, and redraw the arrow."
  286.   (interactive)
  287.   (redraw-display)
  288.   (gdb-display-frame))
  289.  
  290. (defun gdb-display-frame (&optional nodisplay noauto)
  291.   "Find, obey and delete the last filename-and-line marker from GDB.
  292. The marker looks like \\032\\032FILENAME:LINE:CHARPOS\\n.
  293. Obeying it means displaying in another window the specified file and line."
  294.   (interactive)
  295.   (gdb-set-buffer)
  296.   (and gdb-last-frame (not nodisplay)
  297.        (or (not gdb-last-frame-displayed-p) (not noauto))
  298.        (progn (gdb-display-line (car gdb-last-frame) (cdr gdb-last-frame))
  299.           (setq gdb-last-frame-displayed-p t))))
  300.  
  301. ;; Make sure the file named TRUE-FILE is in a buffer that appears on the screen
  302. ;; and that its line LINE is visible.
  303. ;; Put the overlay-arrow on the line LINE in that buffer.
  304.  
  305. (defun gdb-display-line (true-file line)
  306.   (let* ((buffer (find-file-noselect true-file))
  307.      (window (display-buffer buffer t))
  308.      (pos))
  309.     (save-excursion
  310.       (set-buffer buffer)
  311.       (save-restriction
  312.     (widen)
  313.     (goto-line line)
  314.     (setq pos (point))
  315.     (setq overlay-arrow-string "=>")
  316.     (or overlay-arrow-position
  317.         (setq overlay-arrow-position (make-marker)))
  318.     (set-marker overlay-arrow-position (point) (current-buffer)))
  319.       (cond ((or (< pos (point-min)) (> pos (point-max)))
  320.          (widen)
  321.          (goto-char pos))))
  322.     (set-window-point window overlay-arrow-position)))
  323.  
  324. (defun gdb-call (command)
  325.   "Invoke gdb COMMAND displaying source in other window."
  326.   (interactive)
  327.   (goto-char (point-max))
  328.   (setq gdb-delete-prompt-marker (point-marker))
  329.   (gdb-set-buffer)
  330.   (send-string (get-buffer-process current-gdb-buffer)
  331.            (concat command "\n")))
  332.  
  333. (defun gdb-maybe-delete-prompt ()
  334.   (if (and gdb-delete-prompt-marker
  335.        (> (point-max) (marker-position gdb-delete-prompt-marker)))
  336.       (let (start)
  337.     (goto-char gdb-delete-prompt-marker)
  338.     (setq start (point))
  339.     (beginning-of-line)
  340.     (delete-region (point) start)
  341.     (setq gdb-delete-prompt-marker nil))))
  342.  
  343. (defun gdb-break ()
  344.   "Set GDB breakpoint at this source line."
  345.   (interactive)
  346.   (let ((file-name (file-name-nondirectory buffer-file-name))
  347.     (line (save-restriction
  348.         (widen)
  349.         (1+ (count-lines 1 (point))))))
  350.     (send-string (get-buffer-process current-gdb-buffer)
  351.          (concat "break " file-name ":" line "\n"))))
  352.  
  353. (defun gdb-read-address()
  354.   "Return a string containing the core-address found in the buffer at point."
  355.   (save-excursion
  356.    (let ((pt (dot)) found begin)
  357.      (setq found (if (search-backward "0x" (- pt 7) t)(dot)))
  358.      (cond (found (forward-char 2)(setq result
  359.             (buffer-substring found
  360.                  (progn (re-search-forward "[^0-9a-f]")
  361.                     (forward-char -1)
  362.                     (dot)))))
  363.        (t (setq begin (progn (re-search-backward "[^0-9]") (forward-char 1)
  364.                  (dot)))
  365.           (forward-char 1)
  366.           (re-search-forward "[^0-9]")
  367.           (forward-char -1)
  368.           (buffer-substring begin (dot)))))))
  369.  
  370.  
  371. (defvar gdb-commands nil
  372.   "List of strings or functions used by send-gdb-command.
  373. It is for customization by you.")
  374.  
  375. (defun send-gdb-command (arg)
  376.  
  377.   "This command reads the number where the cursor is positioned.  It
  378.  then inserts this ADDR at the end of the gdb buffer.  A numeric arg
  379.  selects the ARG'th member COMMAND of the list gdb-print-command.  If
  380.  COMMAND is a string, (format COMMAND ADDR) is inserted, otherwise
  381.  (funcall COMMAND ADDR) is inserted.  eg. \"p (rtx)%s->fld[0].rtint\"
  382.  is a possible string to be a member of gdb-commands.  "
  383.  
  384.  
  385.   (interactive "P")
  386.   (let (comm addr)
  387.     (if arg (setq comm (nth arg gdb-commands)))
  388.     (setq addr (gdb-read-address))
  389.     (if (eq (current-buffer) current-gdb-buffer)
  390.     (set-mark (point)))
  391.     (cond (comm
  392.        (setq comm
  393.          (if (stringp comm) (format comm addr) (funcall comm addr))))
  394.       (t (setq comm addr)))
  395.     (switch-to-buffer current-gdb-buffer)
  396.     (goto-char (dot-max))
  397.     (insert-string comm)))
  398.